/*
 * ExplicaEntitySelectionView.java
 *
 * $Id: ExplicaEntitySelectionView.java,v 1.8 2009-09-17 12:08:39 mario Exp $
 */
package org.ceteca.explica.client.gui;

import java.net.URL;
import java.util.ArrayList;

import org.apache.log4j.Logger;
import org.ceteca.explica.client.ClientContext;
import org.ceteca.explica.client.gui.common.CommonClient;
import org.ceteca.explica.core.InterfaceExplica;
import org.ceteca.explica.core.common.BaseVO;
import org.ceteca.explica.core.common.MultiSelectionSubentityOT;
import org.ceteca.explica.core.installer.EntityLauncher;
import org.ceteca.explica.core.installer.EntityLauncherFactory;
import org.ceteca.explica.core.installer.EntityOT;
import org.ceteca.explica.core.installer.SubentityOT;
import org.ceteca.explica.core.util.LoggerFactory;
import org.ceteca.javaglade.Gui;
import org.ceteca.javaglade.InterfaceGladeGtk;
import org.ceteca.javaglade.InterfaceGladeParser;
import org.ceteca.javaglade.JavaGlade;
import org.ceteca.javaglade.JavaGladeException;
import org.ceteca.javaglade.JavaGladeUtil;
import org.ceteca.javaglade.handlers.GenericHandler;
import org.ceteca.javaglade.toolkit.swt.SwtDialog;
import org.ceteca.javaglade.toolkit.swt.SwtWidget;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StackLayout;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Tree;

/**
 * Helper class that implements the handler for sub-entities selection
 * (magnifying glass buttons).
 * Opens a new window with the list of registries for the chosen sub-entity.
 * This window allows the user to select an existing entity registry or
 * begin the insertion of a new one. 
 * <br/>
 * Responsibilities:
 * <ul>
 * 	<li>Provide a selection of sub-entity event handler.</li>
 *  <li>Show the sub-entity selection dialog to the user.</li>
 * </ul>
 * <br/>
 * @author Mario García García <mario@imagos.es>
 * Copyright (c) 2008 Fundación Centro Tecnolóxico da Carne
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * <br/>
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * <br/>
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
public class ExplicaEntitySelectionView extends GenericHandler {
	private Logger logger;
	private ExplicaEntityView entView;
	private String selectionGuiName;
	private SwtDialog dialog;
	private Gui parentGui;
	private SwtWidget subentityPanel;
	
	/**
	 * Constant value with the logging message for an error ocurred during the 
	 * loading of the entity's helper class.
	 */
	public static final String ERROR_ENTITY_NOHELPERCLASS = "Cannot find the entity's helper class!";
	/**
	 * Constant va lue with the logging message for an error ocurred during the 
	 * instantiation of the entity's helper class.
	 */
	public static final String ERROR_ENTITY_NOHELPERINSTANCE = "An instance of the entity's helper class couldn't be created!";
	
	public ExplicaEntitySelectionView(String name, Gui parentGui) {
		this.logger = LoggerFactory.getLogger(InterfaceGladeParser.JAVAGLADE_LOG_CATEGORY);
		this.selectionGuiName = name;
		this.dialog = null;
		this.parentGui = parentGui;
		this.gui = null;
		this.subentityPanel = null;
	}
	
	public void buildSelectionDialog() {
		URL url = this.getClass().getResource(InterfaceExplica.EXPLICA_SUBENTITY_SELECTION_GLADE_PATH);
		if (url == null) {
			System.err.println("INTERNAL ERROR! NO INTERFACE CONFIGURATION FILE CAN BE FOUND!");
			System.exit(-1);
		}

		// Build the subentity selection window
		try {
			this.logger.info(String.format("Building entity selection javaglade..."));
			this.logger.debug("Name: " + this.selectionGuiName);
			this.logger.debug("Glade path: " + InterfaceExplica.EXPLICA_SUBENTITY_SELECTION_GLADE_PATH);
			this.logger.debug("Parent gui: " + this.parentGui);
			this.logger.debug("Parent gui window: " + this.parentGui.getParentWindow());
			ExplicaGUIBuilder.getInstance().printGUIs(this.logger);
			
			this.gui = ExplicaGUIBuilder.getInstance().buildGUI(
					this.selectionGuiName,
					InterfaceExplica.EXPLICA_SUBENTITY_SELECTION_GLADE_PATH,
					this.parentGui,
					this.parentGui.getParentWindow());

			this.logger.info(String.format("Entity selection javaglade built!"));
			this.gui.printDetailedWidgets(this.logger);
			
			// Get the parent panel where the entity content is embedded
			SwtWidget parent = this.getEntityPanel();
			Composite parentComposite = (Composite)parent.getWidget();
			this.logger.debug("Entity parent panel found: " + parent + "[" + parentComposite.getLayout() + "]");
			parentComposite.setLayout(new FillLayout());
			
			// Get the select button from the subentity selection dialog.
			Button buttonSelect = (Button)this.gui.getWidget(InterfaceExplica.EXPLICA_SUBENTITY_SELECTION_SELECT_BUTTON_NAME);
			
			// Connect the select button to its handler
			ExplicaGUIBuilder.getInstance().connectSignal(InterfaceGladeGtk.GTK_SIGNAL_TYPE_CLICKED, buttonSelect, 
					InterfaceExplica.EXPLICA_SUBENTITY_SELECTION_SELECT_CLICKED_HANDLER, this);
			
			// Get the cancel button from the subentity selection dialog.
			Button buttonCancel = (Button)this.gui.getWidget(InterfaceExplica.EXPLICA_SUBENTITY_SELECTION_CANCEL_BUTTON_NAME);
			
			// Connect the select button to its handler
			ExplicaGUIBuilder.getInstance().connectSignal(InterfaceGladeGtk.GTK_SIGNAL_TYPE_CLICKED, buttonCancel, 
					InterfaceExplica.EXPLICA_SUBENTITY_SELECTION_CANCEL_CLICKED_HANDLER, this);
			
			this.dialog = this.getGui().getDialog(InterfaceExplica.EXPLICA_SUBENTITY_SELECTION_DIALOG_NAME);
			
			// Connect the close dialog event to its handler
			ExplicaGUIBuilder.getInstance().connectSignal(InterfaceGladeGtk.GTK_SIGNAL_TYPE_CLOSE, dialog.getShell(), InterfaceExplica.EXPLICA_SUBENTITY_SELECTION_CLOSE_HANDLER, this);
		}
		catch (JavaGladeException jEx) {
			this.logger.error("Error building entity selection javaglade!", jEx);
			jEx.printStackTrace();
		}
		catch (Exception ex) {
			this.logger.error("Error building entity selection javaglade!", ex);
			ex.printStackTrace();
		}
		
		this.dialog = this.gui.getDialog("dialog_entitySelection");
	}

	public void showSubentitySelection(SubentityOT subentData) {
		this.logger.info("ºººº SHOWING SUBENTITY SELECTION DIALOG: " + subentData.getSubentityData().getKey() + " ºººº");
		this.gui.printDetailedWidgets(this.logger);
		
		// Eliminamos la vista anterior si existe alguna
		this.clearSelectionView();
		
		// Get the main panel of the selection window
		SwtWidget selectionPanel = this.getEntityPanel();
		
		EntityOT entData = subentData.getSubentityData();
		
		Composite parentComposite = (Composite)selectionPanel.getWidget();
		Composite subentityComposite = (Composite)ExplicaGUIBuilder.getInstance().getToolkit().
			emptyPanel(parentComposite, selectionPanel.getWidgetName().concat("_").concat(entData.getKey()));
		subentityComposite.setLayout(new FillLayout());
		this.gui.addWidget(selectionPanel.getWidgetName().concat("_").concat(entData.getKey()), subentityComposite, selectionPanel.getWidgetName());
		
		this.subentityPanel = this.gui.getSwtWidget(selectionPanel.getWidgetName().concat("_").concat(entData.getKey()));

		// Get the entity launcher instance that will handle the entity events
		EntityLauncher entLauncher = this.getEntLauncher(subentData);
		
		this.logger.info("ºººº GOT ENTITY LAUNCHER: " + entLauncher + " ºººº");
		
		if (entLauncher != null) {
			entLauncher.initEntityLauncher(this.logger, this.gui, this.subentityPanel);
		}
		else
			this.logger.error(ERROR_ENTITY_NOHELPERINSTANCE);
		
		ClientContext.getInstance().printEntityLaunchers(this.logger);
		
		this.logger.debug(String.format("Got subentity launcher [%s]: %s", subentData.getSubentityData().getKey(), entLauncher));
		this.gui.printDetailedWidgets(this.logger);
		
		// Add the entity contents to the entity selection window
		// For building the entity contents the ExplicaEntityView class will
		// be used. In this case the contents will be embedded into the dialog
		this.entView = entLauncher.buildEntity();
		
		Composite parentPanel = selectionPanel != null?(Composite)selectionPanel.getWidget():null;
		if (parentPanel != null) {
			parentPanel.layout(true);
		
			// Distribute the entity columns to fit all the available dialog width 
			this.logger.debug(String.format("Got entity content panel: %s --> (%d, %d px) [%s]", 
					entData.getName(), parentPanel.computeSize(SWT.DEFAULT, SWT.DEFAULT).x, parentPanel.computeSize(SWT.DEFAULT, SWT.DEFAULT).y, parentPanel.getLayout()));
		
			this.entView.distributeColumns(parentPanel.computeSize(SWT.DEFAULT, SWT.DEFAULT).x - 10);
			
			// Get the entity table widget and show the selected registries
			Tree entityTree = this.entView.getEntityTreeWidget();
			entityTree.showSelection();

			this.logger.debug(String.format("SELECTION PANEL: %s --> %s", parentPanel.getLayout(), this.entView.getEntityPanel()));
			
			this.gui.printWidgetTree(this.gui.getRootWidget(), this.logger);
			this.logger.debug("Entity view panel: " + entView.getEntityPanel());
			this.logger.debug("Showing entity panel: " + parentPanel.getChildren()[0]);
		}
		
		this.logger.info(String.format("Opening entity selection dialog window: %s", entData.getName()));
		
		// Get the select button from the subentity selection dialog.
		Button buttonSelect = (Button)this.gui.getWidget(InterfaceExplica.EXPLICA_SUBENTITY_SELECTION_SELECT_BUTTON_NAME);
		buttonSelect.setData(subentData);
		
		// Get the cancel button from the subentity selection dialog.
		Button buttonCancel = (Button)this.gui.getWidget(InterfaceExplica.EXPLICA_SUBENTITY_SELECTION_CANCEL_BUTTON_NAME);
		buttonCancel.setData(subentData);
		
		if (subentData instanceof MultiSelectionSubentityOT && this.getEntLauncher(subentData) instanceof CommonClient){
			this.logger.debug("Query entities with null parent field: "+subentData.getParentFieldId());
			ArrayList<BaseVO> lregs=((CommonClient)this.getEntLauncher(subentData)).
				queryFreeEntities((MultiSelectionSubentityOT)subentData);
			this.getEntLauncher(subentData).setRegistries(lregs);
			if (lregs!=null)
				this.logger.debug("Registries retrieved: "+lregs.size());
			if (entView!=null)
					this.entView.updateView();
		}
/*		else{
			if (entView!=null)
				this.entView.showEntityView();
		}
*/
		
		// Show the edit product window
		this.dialog.open();
	}
	
	public void clearSelectionView() {
		if (this.subentityPanel != null) {
			this.gui.removeWidget(this.subentityPanel.getWidgetName());
		}
	}
	
	public void closeSelectionView() {
		if (this.dialog != null)
			this.dialog.close();
	}
	
	public void dispose() {
		if (this.dialog != null)
			this.dialog.dispose();
	}
	
	/**
	 * Handler for the entity selection dialog's Select button clicked event.
	 * Returns the selected entity registry.
	 * @param e Event, select button clicked event data.
	 */
	public void on_entitySelectionSelectButton_clicked(Event e) {
		System.out.println("SUBENTITY SELECTED: " + e.widget.getData());
		SubentityOT subentData = (SubentityOT)e.widget.getData();
		System.out.println(String.format("SUBENTITY SELECTED: %s --> %s", 
				subentData.getParentFieldId(), subentData.getParentEntity()));
		
		// Get the parent entity launcher from which the selection window was requested
		EntityLauncher parentEntityLauncher = null;
		if (subentData instanceof MultiSelectionSubentityOT)
			parentEntityLauncher = ((MultiSelectionSubentityOT)subentData).getSubentityLauncher();
		else
			parentEntityLauncher = subentData.getParentEntity();
		
		
		// Get the entity launcher instance that will handle the entity events
		EntityLauncher entLauncher = this.getEntLauncher(subentData);
		
		this.logger.debug(String.format("SUBENTITY SELECTED: %s --> %s", e.widget.getData(), entLauncher));
		this.logger.debug(String.format("SUBENTITY SELECTED PARENT INFO: %s --> %s", 
				subentData.getParentFieldId(), subentData.getParentEntity()));
		
		// Call the parentEntity launcher selectSubentity() method for
		// updating the selecting subentity in the parent's data.
		if (parentEntityLauncher != null) {
			if (subentData instanceof MultiSelectionSubentityOT && parentEntityLauncher instanceof CommonClient)
				((CommonClient)parentEntityLauncher).addSubentity(entLauncher.getSelectedEntity(), (MultiSelectionSubentityOT)subentData);
			else
				parentEntityLauncher.selectSubentity(subentData.getParentFieldId(), entLauncher.getSelectedEntity());
		}
		
		this.dialog.close();
	}
	
	/**
	 * Handler for the entity selection dialog's Cancel button clicked event.
	 * Returns with no selected registry.
	 * @param e Event, cancel button clicked event data.
	 */
	public void on_entitySelectionCancelButton_clicked(Event e) {
		this.dialog.close();
	}
	
	/**
	 * Handler for the entity selection dialog close event.
	 * Clears and relases the entity view component.
	 * @param e Event, close event data.
	 */
	public void on_entitySelection_close(Event e) {
		this.logger.debug("Closing selection dialog" + this.selectionGuiName + " --> " + e.widget);
		ClientContext.getInstance().releaseEntityView(this.entView);
	}
	
	private EntityLauncherFactory getEntityLauncherFactory(EntityOT entOT) {
		EntityLauncherFactory factory = null;
		if (entOT != null && entOT.getKey() != null && entOT.getKey().length() > 0) {
			factory = ClientContext.getInstance().getEntityLauncherFactory(entOT.getKey());
			if (factory == null ) {
				ClientContext.getInstance().initEntityLauncherFactory(entOT, this.logger);
				factory = ClientContext.getInstance().getEntityLauncherFactory(entOT.getKey());
			}
		}
		
		return factory;
	}
	
	private SwtWidget getEntityPanel() {
		if (this.gui != null) {
			this.gui.printWidgets(this.logger);
			return this.gui.getSwtWidget(InterfaceExplica.EXPLICA_ENTITY_PANEL_NAME);
		}
		else {
			this.logger.debug("Cannot get entity panel! Gui is NULL!");
			return null;
		}
	}
	
	private EntityLauncher getEntLauncher(SubentityOT subentData) {
		// Get the entity launcher factory for creating a new entity launcher
		// that will handle the entity events.
		EntityLauncherFactory factory = this.getEntityLauncherFactory(subentData.getSubentityData());
		this.logger.debug("Entity launcher factory got: " + subentData.getSubentityData().getKey() + " --> " + factory);
		
		// Get the parent panel where the entity content is embedded
		SwtWidget parentWidget = this.getEntityPanel();
		this.logger.debug("Parent widget got: " + subentData.getSubentityData().getKey() + " --> " + parentWidget);
		
		// Get the entity launcher instance that will handle the entity events
		EntityLauncher entLauncher = factory.getEntityLauncher(parentWidget);
		
		return entLauncher;
	}
	
	/**
	 * Handler for the subentity selection buttons (magnifying glass buttons) clicked.
	 * Shows the selection dialog for selecting a valid instance of a subentity.
	 * @param e Event, magnifying glass button clicked event data.
	 */
	public void on_entitySelectionButton_clicked(Event e) {
		this.logger.debug("Clickkkkkkk 1");
		ClientContext.getInstance().getLogger().debug("Clickkkkkkk 2");
		Button subentityButton = (Button)e.widget;
		
		// Get the entity data corresponding to the clicked entity selection button
		SubentityOT entData = (SubentityOT)subentityButton.getData();
		
		this.logger.debug("Subentity clicked button data: " + entData);
		
		// Get the entity launcher instance that will handle the entity events
		EntityLauncher entLauncher = entData.getParentEntity();
		
		this.logger.debug("Subentity entity launcher got: " + entLauncher);
		
		entLauncher.showSelectionDialog(entData);
	}
	
	/**
	 * Returns tag Id assigned to CVS source file.
	 */
	public static String getRevision() {
		return "$Id: ExplicaEntitySelectionView.java,v 1.8 2009-09-17 12:08:39 mario Exp $";
	}	
}
